"""
Flask WebSocket实时通信示例 - 展示实时聊天、通知推送等功能
包含WebSocket连接管理、房间管理、消息广播等特性
"""

from flask import Flask, request, jsonify, render_template_string
from flask_socketio import SocketIO, emit, join_room, leave_room, rooms
import os
import sys
import time
import json
from datetime import datetime, timedelta
from typing import Dict, Any, List, Optional, Set
from enum import Enum
from dataclasses import dataclass, asdict
import threading
from collections import defaultdict

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from python_backend_toolkit.auth import JWTAuth
from python_backend_toolkit.cache import CacheManager, MemoryCache
from python_backend_toolkit.database import Base, BaseModel, DatabaseSession
from python_backend_toolkit.logging import get_logger, setup_logging
from python_backend_toolkit.utils import generate_uuid, format_datetime
from python_backend_toolkit.api.responses import SuccessResponse, ErrorResponse

from sqlalchemy import Column, Integer, String, Text, DateTime, Boolean, Enum as SQLEnum


# ========================================================================
# 数据模型和枚举
# ========================================================================

class MessageType(Enum):
    """消息类型"""
    TEXT = "text"
    IMAGE = "image"
    FILE = "file"
    SYSTEM = "system"
    NOTIFICATION = "notification"


class RoomType(Enum):
    """房间类型"""
    PUBLIC = "public"
    PRIVATE = "private"
    GROUP = "group"


class UserStatus(Enum):
    """用户状态"""
    ONLINE = "online"
    OFFLINE = "offline"
    AWAY = "away"
    BUSY = "busy"


@dataclass
class OnlineUser:
    """在线用户"""
    user_id: int
    username: str
    socket_id: str
    status: UserStatus
    joined_at: datetime
    last_activity: datetime
    rooms: Set[str]
    
    def to_dict(self):
        data = asdict(self)
        data['joined_at'] = self.joined_at.isoformat()
        data['last_activity'] = self.last_activity.isoformat()
        data['rooms'] = list(self.rooms)
        data['status'] = self.status.value
        return data


class ChatRoom(BaseModel):
    """聊天房间模型"""
    __tablename__ = 'websocket_rooms'
    
    name = Column(String(100), nullable=False)
    description = Column(Text)
    room_type = Column(SQLEnum(RoomType), default=RoomType.PUBLIC)
    creator_id = Column(Integer, nullable=False)
    max_users = Column(Integer, default=100)
    is_active = Column(Boolean, default=True)
    password = Column(String(255))  # 私有房间密码


class ChatMessage(BaseModel):
    """聊天消息模型"""
    __tablename__ = 'websocket_messages'
    
    room_id = Column(String(50), nullable=False)
    user_id = Column(Integer, nullable=False)
    username = Column(String(50), nullable=False)
    message_type = Column(SQLEnum(MessageType), default=MessageType.TEXT)
    content = Column(Text, nullable=False)
    metadata = Column(Text)  # JSON格式的额外数据


# ========================================================================
# WebSocket连接管理器
# ========================================================================

class ConnectionManager:
    """WebSocket连接管理器"""
    
    def __init__(self):
        self.online_users: Dict[str, OnlineUser] = {}  # socket_id -> OnlineUser
        self.user_sockets: Dict[int, str] = {}  # user_id -> socket_id
        self.room_users: Dict[str, Set[str]] = defaultdict(set)  # room_id -> set of socket_ids
        self.logger = get_logger("ConnectionManager")
        self.cache = MemoryCache()
    
    def add_user(self, socket_id: str, user_id: int, username: str):
        """添加在线用户"""
        # 如果用户已经在线，先移除旧连接
        if user_id in self.user_sockets:
            old_socket_id = self.user_sockets[user_id]
            self.remove_user(old_socket_id)
        
        user = OnlineUser(
            user_id=user_id,
            username=username,
            socket_id=socket_id,
            status=UserStatus.ONLINE,
            joined_at=datetime.utcnow(),
            last_activity=datetime.utcnow(),
            rooms=set()
        )
        
        self.online_users[socket_id] = user
        self.user_sockets[user_id] = socket_id
        
        self.logger.info(
            "User connected",
            user_id=user_id,
            username=username,
            socket_id=socket_id
        )
    
    def remove_user(self, socket_id: str):
        """移除在线用户"""
        if socket_id in self.online_users:
            user = self.online_users[socket_id]
            
            # 从所有房间移除
            for room_id in user.rooms.copy():
                self.leave_room(socket_id, room_id)
            
            # 移除用户记录
            del self.online_users[socket_id]
            if user.user_id in self.user_sockets:
                del self.user_sockets[user.user_id]
            
            self.logger.info(
                "User disconnected",
                user_id=user.user_id,
                username=user.username,
                socket_id=socket_id
            )
    
    def get_user(self, socket_id: str) -> Optional[OnlineUser]:
        """获取在线用户"""
        return self.online_users.get(socket_id)
    
    def get_user_by_id(self, user_id: int) -> Optional[OnlineUser]:
        """根据用户ID获取在线用户"""
        socket_id = self.user_sockets.get(user_id)
        if socket_id:
            return self.online_users.get(socket_id)
        return None
    
    def update_user_activity(self, socket_id: str):
        """更新用户活动时间"""
        if socket_id in self.online_users:
            self.online_users[socket_id].last_activity = datetime.utcnow()
    
    def update_user_status(self, socket_id: str, status: UserStatus):
        """更新用户状态"""
        if socket_id in self.online_users:
            self.online_users[socket_id].status = status
    
    def join_room(self, socket_id: str, room_id: str):
        """用户加入房间"""
        if socket_id in self.online_users:
            user = self.online_users[socket_id]
            user.rooms.add(room_id)
            self.room_users[room_id].add(socket_id)
            
            self.logger.info(
                "User joined room",
                user_id=user.user_id,
                username=user.username,
                room_id=room_id
            )
    
    def leave_room(self, socket_id: str, room_id: str):
        """用户离开房间"""
        if socket_id in self.online_users:
            user = self.online_users[socket_id]
            user.rooms.discard(room_id)
            self.room_users[room_id].discard(socket_id)
            
            # 如果房间为空，清理房间记录
            if not self.room_users[room_id]:
                del self.room_users[room_id]
            
            self.logger.info(
                "User left room",
                user_id=user.user_id,
                username=user.username,
                room_id=room_id
            )
    
    def get_room_users(self, room_id: str) -> List[OnlineUser]:
        """获取房间内的用户"""
        socket_ids = self.room_users.get(room_id, set())
        return [self.online_users[sid] for sid in socket_ids if sid in self.online_users]
    
    def get_online_users(self) -> List[OnlineUser]:
        """获取所有在线用户"""
        return list(self.online_users.values())
    
    def get_user_rooms(self, socket_id: str) -> Set[str]:
        """获取用户加入的房间"""
        if socket_id in self.online_users:
            return self.online_users[socket_id].rooms
        return set()


# ========================================================================
# 消息处理器
# ========================================================================

class MessageHandler:
    """消息处理器"""
    
    def __init__(self, socketio: SocketIO, connection_manager: ConnectionManager):
        self.socketio = socketio
        self.connection_manager = connection_manager
        self.logger = get_logger("MessageHandler")
        
        # 初始化数据库
        self.db_session = DatabaseSession(
            database_url="sqlite:///websocket_chat.db",
            echo=False
        )
        self.db_session.create_tables()
    
    def handle_text_message(self, socket_id: str, room_id: str, content: str, metadata: Dict = None):
        """处理文本消息"""
        user = self.connection_manager.get_user(socket_id)
        if not user:
            return
        
        # 保存消息到数据库
        message = self._save_message(
            room_id=room_id,
            user_id=user.user_id,
            username=user.username,
            message_type=MessageType.TEXT,
            content=content,
            metadata=metadata
        )
        
        # 广播消息到房间
        message_data = {
            "id": message.id,
            "room_id": room_id,
            "user_id": user.user_id,
            "username": user.username,
            "message_type": MessageType.TEXT.value,
            "content": content,
            "metadata": metadata or {},
            "timestamp": message.created_at.isoformat()
        }
        
        self.socketio.emit('new_message', message_data, room=room_id)
        
        self.logger.info(
            "Text message sent",
            user_id=user.user_id,
            room_id=room_id,
            message_id=message.id
        )
    
    def handle_system_message(self, room_id: str, content: str, metadata: Dict = None):
        """处理系统消息"""
        # 保存系统消息
        message = self._save_message(
            room_id=room_id,
            user_id=0,  # 系统用户ID
            username="System",
            message_type=MessageType.SYSTEM,
            content=content,
            metadata=metadata
        )
        
        # 广播系统消息
        message_data = {
            "id": message.id,
            "room_id": room_id,
            "user_id": 0,
            "username": "System",
            "message_type": MessageType.SYSTEM.value,
            "content": content,
            "metadata": metadata or {},
            "timestamp": message.created_at.isoformat()
        }
        
        self.socketio.emit('system_message', message_data, room=room_id)
        
        self.logger.info(
            "System message sent",
            room_id=room_id,
            message_id=message.id
        )
    
    def handle_notification(self, user_id: int, title: str, content: str, metadata: Dict = None):
        """处理通知消息"""
        user = self.connection_manager.get_user_by_id(user_id)
        if not user:
            return
        
        notification_data = {
            "id": generate_uuid(),
            "title": title,
            "content": content,
            "metadata": metadata or {},
            "timestamp": datetime.utcnow().isoformat()
        }
        
        self.socketio.emit('notification', notification_data, room=user.socket_id)
        
        self.logger.info(
            "Notification sent",
            user_id=user_id,
            title=title
        )
    
    def get_room_messages(self, room_id: str, limit: int = 50, offset: int = 0) -> List[Dict]:
        """获取房间消息历史"""
        session = self.db_session.get_session()
        
        try:
            messages = session.query(ChatMessage).filter(
                ChatMessage.room_id == room_id
            ).order_by(ChatMessage.created_at.desc()).offset(offset).limit(limit).all()
            
            result = []
            for message in reversed(messages):  # 按时间正序返回
                data = {
                    "id": message.id,
                    "room_id": message.room_id,
                    "user_id": message.user_id,
                    "username": message.username,
                    "message_type": message.message_type.value,
                    "content": message.content,
                    "metadata": json.loads(message.metadata) if message.metadata else {},
                    "timestamp": message.created_at.isoformat()
                }
                result.append(data)
            
            return result
            
        finally:
            session.close()
    
    def _save_message(self, room_id: str, user_id: int, username: str,
                     message_type: MessageType, content: str, metadata: Dict = None) -> ChatMessage:
        """保存消息到数据库"""
        session = self.db_session.get_session()
        
        try:
            message = ChatMessage(
                room_id=room_id,
                user_id=user_id,
                username=username,
                message_type=message_type,
                content=content,
                metadata=json.dumps(metadata) if metadata else None
            )
            
            session.add(message)
            session.commit()
            
            return message
            
        finally:
            session.close()


# ========================================================================
# Flask应用和WebSocket事件
# ========================================================================

def create_websocket_app() -> Flask:
    """创建WebSocket应用"""
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'websocket-demo-secret'
    
    # 初始化SocketIO
    socketio = SocketIO(
        app,
        cors_allowed_origins="*",
        logger=True,
        engineio_logger=True
    )
    
    # 初始化日志
    setup_logging()
    logger = get_logger("WebSocketApp")
    
    # 初始化组件
    jwt_auth = JWTAuth(secret_key=app.config['SECRET_KEY'])
    connection_manager = ConnectionManager()
    message_handler = MessageHandler(socketio, connection_manager)
    
    # ========================================================================
    # WebSocket事件处理
    # ========================================================================
    
    @socketio.on('connect')
    def handle_connect(auth):
        """处理连接事件"""
        try:
            # 验证JWT令牌
            if not auth or 'token' not in auth:
                logger.warning("Connection rejected: no token")
                return False
            
            token = auth['token']
            payload = jwt_auth.decode_token(token)
            user_id = payload.get('user_id')
            username = payload.get('username')
            
            if not user_id or not username:
                logger.warning("Connection rejected: invalid token payload")
                return False
            
            # 添加用户到连接管理器
            connection_manager.add_user(request.sid, user_id, username)
            
            # 发送连接成功消息
            emit('connected', {
                'user_id': user_id,
                'username': username,
                'socket_id': request.sid,
                'timestamp': datetime.utcnow().isoformat()
            })
            
            logger.info(
                "User connected via WebSocket",
                user_id=user_id,
                username=username,
                socket_id=request.sid
            )
            
        except Exception as e:
            logger.error("Connection error", error=str(e))
            return False
    
    @socketio.on('disconnect')
    def handle_disconnect():
        """处理断开连接事件"""
        user = connection_manager.get_user(request.sid)
        if user:
            # 通知用户离开的房间
            for room_id in user.rooms.copy():
                message_handler.handle_system_message(
                    room_id=room_id,
                    content=f"{user.username} 离开了房间"
                )
        
        connection_manager.remove_user(request.sid)
        
        logger.info("User disconnected", socket_id=request.sid)
    
    @socketio.on('join_room')
    def handle_join_room(data):
        """处理加入房间事件"""
        try:
            room_id = data.get('room_id')
            if not room_id:
                emit('error', {'message': 'Room ID is required'})
                return
            
            user = connection_manager.get_user(request.sid)
            if not user:
                emit('error', {'message': 'User not found'})
                return
            
            # 加入房间
            join_room(room_id)
            connection_manager.join_room(request.sid, room_id)
            
            # 发送房间信息
            room_users = connection_manager.get_room_users(room_id)
            emit('room_joined', {
                'room_id': room_id,
                'users': [u.to_dict() for u in room_users],
                'timestamp': datetime.utcnow().isoformat()
            })
            
            # 发送消息历史
            messages = message_handler.get_room_messages(room_id, limit=50)
            emit('message_history', {
                'room_id': room_id,
                'messages': messages
            })
            
            # 通知其他用户
            message_handler.handle_system_message(
                room_id=room_id,
                content=f"{user.username} 加入了房间"
            )
            
            # 更新用户活动时间
            connection_manager.update_user_activity(request.sid)
            
        except Exception as e:
            logger.error("Join room error", error=str(e))
            emit('error', {'message': 'Failed to join room'})
    
    @socketio.on('leave_room')
    def handle_leave_room(data):
        """处理离开房间事件"""
        try:
            room_id = data.get('room_id')
            if not room_id:
                emit('error', {'message': 'Room ID is required'})
                return
            
            user = connection_manager.get_user(request.sid)
            if not user:
                emit('error', {'message': 'User not found'})
                return
            
            # 离开房间
            leave_room(room_id)
            connection_manager.leave_room(request.sid, room_id)
            
            # 通知其他用户
            message_handler.handle_system_message(
                room_id=room_id,
                content=f"{user.username} 离开了房间"
            )
            
            emit('room_left', {
                'room_id': room_id,
                'timestamp': datetime.utcnow().isoformat()
            })
            
            # 更新用户活动时间
            connection_manager.update_user_activity(request.sid)
            
        except Exception as e:
            logger.error("Leave room error", error=str(e))
            emit('error', {'message': 'Failed to leave room'})
    
    @socketio.on('send_message')
    def handle_send_message(data):
        """处理发送消息事件"""
        try:
            room_id = data.get('room_id')
            content = data.get('content')
            message_type = data.get('type', 'text')
            metadata = data.get('metadata', {})
            
            if not room_id or not content:
                emit('error', {'message': 'Room ID and content are required'})
                return
            
            user = connection_manager.get_user(request.sid)
            if not user:
                emit('error', {'message': 'User not found'})
                return
            
            # 检查用户是否在房间中
            if room_id not in user.rooms:
                emit('error', {'message': 'You are not in this room'})
                return
            
            # 处理消息
            if message_type == 'text':
                message_handler.handle_text_message(
                    socket_id=request.sid,
                    room_id=room_id,
                    content=content,
                    metadata=metadata
                )
            
            # 更新用户活动时间
            connection_manager.update_user_activity(request.sid)
            
        except Exception as e:
            logger.error("Send message error", error=str(e))
            emit('error', {'message': 'Failed to send message'})
    
    @socketio.on('update_status')
    def handle_update_status(data):
        """处理更新状态事件"""
        try:
            status_str = data.get('status')
            if not status_str:
                emit('error', {'message': 'Status is required'})
                return
            
            try:
                status = UserStatus(status_str)
            except ValueError:
                emit('error', {'message': 'Invalid status'})
                return
            
            user = connection_manager.get_user(request.sid)
            if not user:
                emit('error', {'message': 'User not found'})
                return
            
            # 更新状态
            connection_manager.update_user_status(request.sid, status)
            
            # 通知所有房间
            for room_id in user.rooms:
                socketio.emit('user_status_updated', {
                    'user_id': user.user_id,
                    'username': user.username,
                    'status': status.value,
                    'timestamp': datetime.utcnow().isoformat()
                }, room=room_id)
            
            emit('status_updated', {
                'status': status.value,
                'timestamp': datetime.utcnow().isoformat()
            })
            
        except Exception as e:
            logger.error("Update status error", error=str(e))
            emit('error', {'message': 'Failed to update status'})
    
    @socketio.on('get_online_users')
    def handle_get_online_users():
        """处理获取在线用户事件"""
        try:
            online_users = connection_manager.get_online_users()
            emit('online_users', {
                'users': [u.to_dict() for u in online_users],
                'count': len(online_users),
                'timestamp': datetime.utcnow().isoformat()
            })
            
        except Exception as e:
            logger.error("Get online users error", error=str(e))
            emit('error', {'message': 'Failed to get online users'})
    
    # ========================================================================
    # HTTP API端点
    # ========================================================================
    
    @app.route('/')
    def index():
        """主页 - WebSocket聊天界面"""
        html_template = """
        <!DOCTYPE html>
        <html>
        <head>
            <title>WebSocket Chat Demo</title>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
            <style>
                body { font-family: Arial, sans-serif; margin: 20px; }
                .container { max-width: 800px; margin: 0 auto; }
                .chat-box { border: 1px solid #ccc; height: 400px; overflow-y: scroll; padding: 10px; margin: 10px 0; }
                .message { margin: 5px 0; padding: 5px; border-radius: 5px; }
                .message.user { background-color: #e3f2fd; }
                .message.system { background-color: #fff3e0; font-style: italic; }
                .input-group { display: flex; margin: 10px 0; }
                .input-group input { flex: 1; padding: 10px; margin-right: 10px; }
                .input-group button { padding: 10px 20px; }
                .status { margin: 10px 0; padding: 10px; background-color: #f5f5f5; border-radius: 5px; }
                .users-list { border: 1px solid #ccc; padding: 10px; margin: 10px 0; max-height: 200px; overflow-y: scroll; }
            </style>
        </head>
        <body>
            <div class="container">
                <h1>WebSocket Chat Demo</h1>
                
                <div class="status" id="status">
                    状态: 未连接
                </div>
                
                <div class="input-group">
                    <input type="text" id="token" placeholder="JWT Token" style="flex: 2;">
                    <button onclick="connect()">连接</button>
                    <button onclick="disconnect()">断开</button>
                </div>
                
                <div class="input-group">
                    <input type="text" id="roomId" placeholder="房间ID" value="general">
                    <button onclick="joinRoom()">加入房间</button>
                    <button onclick="leaveRoom()">离开房间</button>
                </div>
                
                <div class="users-list">
                    <h3>在线用户</h3>
                    <div id="usersList"></div>
                </div>
                
                <div class="chat-box" id="chatBox"></div>
                
                <div class="input-group">
                    <input type="text" id="messageInput" placeholder="输入消息..." onkeypress="handleKeyPress(event)">
                    <button onclick="sendMessage()">发送</button>
                </div>
            </div>
            
            <script>
                let socket = null;
                let currentRoom = null;
                
                function connect() {
                    const token = document.getElementById('token').value;
                    if (!token) {
                        alert('请输入JWT Token');
                        return;
                    }
                    
                    socket = io({
                        auth: { token: token }
                    });
                    
                    socket.on('connect', () => {
                        updateStatus('已连接');
                    });
                    
                    socket.on('disconnect', () => {
                        updateStatus('已断开');
                    });
                    
                    socket.on('connected', (data) => {
                        addMessage('系统', `欢迎 ${data.username}！`, 'system');
                    });
                    
                    socket.on('new_message', (data) => {
                        addMessage(data.username, data.content, 'user');
                    });
                    
                    socket.on('system_message', (data) => {
                        addMessage('系统', data.content, 'system');
                    });
                    
                    socket.on('room_joined', (data) => {
                        currentRoom = data.room_id;
                        updateStatus(`已加入房间: ${data.room_id}`);
                        updateUsersList(data.users);
                    });
                    
                    socket.on('room_left', (data) => {
                        currentRoom = null;
                        updateStatus('已离开房间');
                        updateUsersList([]);
                    });
                    
                    socket.on('message_history', (data) => {
                        const chatBox = document.getElementById('chatBox');
                        chatBox.innerHTML = '';
                        data.messages.forEach(msg => {
                            addMessage(msg.username, msg.content, msg.message_type);
                        });
                    });
                    
                    socket.on('online_users', (data) => {
                        updateUsersList(data.users);
                    });
                    
                    socket.on('error', (data) => {
                        alert('错误: ' + data.message);
                    });
                }
                
                function disconnect() {
                    if (socket) {
                        socket.disconnect();
                        socket = null;
                        updateStatus('未连接');
                        updateUsersList([]);
                    }
                }
                
                function joinRoom() {
                    if (!socket) {
                        alert('请先连接');
                        return;
                    }
                    
                    const roomId = document.getElementById('roomId').value;
                    if (!roomId) {
                        alert('请输入房间ID');
                        return;
                    }
                    
                    socket.emit('join_room', { room_id: roomId });
                }
                
                function leaveRoom() {
                    if (!socket || !currentRoom) {
                        alert('未在任何房间中');
                        return;
                    }
                    
                    socket.emit('leave_room', { room_id: currentRoom });
                }
                
                function sendMessage() {
                    if (!socket || !currentRoom) {
                        alert('请先加入房间');
                        return;
                    }
                    
                    const input = document.getElementById('messageInput');
                    const content = input.value.trim();
                    if (!content) return;
                    
                    socket.emit('send_message', {
                        room_id: currentRoom,
                        content: content,
                        type: 'text'
                    });
                    
                    input.value = '';
                }
                
                function handleKeyPress(event) {
                    if (event.key === 'Enter') {
                        sendMessage();
                    }
                }
                
                function updateStatus(status) {
                    document.getElementById('status').textContent = '状态: ' + status;
                }
                
                function addMessage(username, content, type) {
                    const chatBox = document.getElementById('chatBox');
                    const messageDiv = document.createElement('div');
                    messageDiv.className = `message ${type}`;
                    messageDiv.innerHTML = `<strong>${username}:</strong> ${content}`;
                    chatBox.appendChild(messageDiv);
                    chatBox.scrollTop = chatBox.scrollHeight;
                }
                
                function updateUsersList(users) {
                    const usersList = document.getElementById('usersList');
                    usersList.innerHTML = users.map(user => 
                        `<div>${user.username} (${user.status})</div>`
                    ).join('');
                }
                
                // 定期获取在线用户
                setInterval(() => {
                    if (socket && socket.connected) {
                        socket.emit('get_online_users');
                    }
                }, 10000);
            </script>
        </body>
        </html>
        """
        return html_template
    
    @app.route('/auth/login', methods=['POST'])
    def login():
        """用户登录（生成JWT令牌）"""
        try:
            data = request.get_json()
            username = data.get('username')
            
            if not username:
                return jsonify(ErrorResponse.create(
                    message="Username is required"
                ).dict()), 400
            
            # 简化的认证（实际应用中应该验证密码）
            user_id = hash(username) % 10000  # 简单的用户ID生成
            
            token = jwt_auth.generate_token({
                'user_id': user_id,
                'username': username
            })
            
            response = SuccessResponse.create(
                data={
                    "user_id": user_id,
                    "username": username,
                    "token": token
                },
                message="Login successful"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Login error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Login failed"
            ).dict()), 500
    
    @app.route('/api/rooms/<room_id>/messages', methods=['GET'])
    def get_room_messages(room_id: str):
        """获取房间消息历史"""
        try:
            limit = min(int(request.args.get('limit', 50)), 100)
            offset = int(request.args.get('offset', 0))
            
            messages = message_handler.get_room_messages(room_id, limit, offset)
            
            response = SuccessResponse.create(
                data={
                    "room_id": room_id,
                    "messages": messages,
                    "limit": limit,
                    "offset": offset
                },
                message="Messages retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Get messages error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to retrieve messages"
            ).dict()), 500
    
    @app.route('/api/users/online', methods=['GET'])
    def get_online_users():
        """获取在线用户列表"""
        try:
            online_users = connection_manager.get_online_users()
            
            response = SuccessResponse.create(
                data={
                    "users": [u.to_dict() for u in online_users],
                    "count": len(online_users)
                },
                message="Online users retrieved successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Get online users error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to retrieve online users"
            ).dict()), 500
    
    @app.route('/api/notification', methods=['POST'])
    def send_notification():
        """发送通知"""
        try:
            data = request.get_json()
            user_id = data.get('user_id')
            title = data.get('title')
            content = data.get('content')
            metadata = data.get('metadata', {})
            
            if not all([user_id, title, content]):
                return jsonify(ErrorResponse.create(
                    message="user_id, title and content are required"
                ).dict()), 400
            
            message_handler.handle_notification(user_id, title, content, metadata)
            
            response = SuccessResponse.create(
                message="Notification sent successfully"
            )
            return jsonify(response.dict())
            
        except Exception as e:
            logger.error("Send notification error", error=str(e))
            return jsonify(ErrorResponse.create(
                message="Failed to send notification"
            ).dict()), 500
    
    @app.route('/health', methods=['GET'])
    def health_check():
        """健康检查"""
        online_count = len(connection_manager.get_online_users())
        
        return jsonify({
            "status": "healthy",
            "timestamp": datetime.utcnow().isoformat(),
            "websocket": {
                "online_users": online_count,
                "active_rooms": len(connection_manager.room_users)
            }
        })
    
    @app.route('/info', methods=['GET'])
    def app_info():
        """应用信息"""
        return jsonify({
            "name": "WebSocket Real-time Communication Demo",
            "version": "1.0.0",
            "description": "WebSocket实时通信示例 - 聊天、通知推送等功能",
            "features": [
                "实时聊天",
                "房间管理",
                "用户状态管理",
                "消息历史",
                "通知推送",
                "在线用户列表",
                "JWT认证",
                "连接管理"
            ],
            "websocket_events": {
                "client_to_server": [
                    "join_room - 加入房间",
                    "leave_room - 离开房间",
                    "send_message - 发送消息",
                    "update_status - 更新状态",
                    "get_online_users - 获取在线用户"
                ],
                "server_to_client": [
                    "connected - 连接成功",
                    "new_message - 新消息",
                    "system_message - 系统消息",
                    "notification - 通知",
                    "room_joined - 加入房间成功",
                    "room_left - 离开房间",
                    "user_status_updated - 用户状态更新",
                    "online_users - 在线用户列表"
                ]
            },
            "http_endpoints": [
                "POST /auth/login - 用户登录",
                "GET  /api/rooms/<id>/messages - 获取房间消息",
                "GET  /api/users/online - 获取在线用户",
                "POST /api/notification - 发送通知"
            ]
        })
    
    # 将socketio实例附加到app
    app.socketio = socketio
    
    return app


if __name__ == '__main__':
    app = create_websocket_app()
    
    print("=" * 60)
    print("Flask WebSocket Real-time Communication Demo")
    print("=" * 60)
    print("WebSocket实时通信演示:")
    print("  功能特性:")
    print("    - 实时聊天")
    print("    - 房间管理")
    print("    - 用户状态管理")
    print("    - 消息历史记录")
    print("    - 通知推送")
    print("    - 在线用户列表")
    print("    - JWT认证")
    print("    - 连接管理")
    print()
    print("  WebSocket事件:")
    print("    客户端 -> 服务器:")
    print("      join_room - 加入房间")
    print("      leave_room - 离开房间")
    print("      send_message - 发送消息")
    print("      update_status - 更新状态")
    print("    服务器 -> 客户端:")
    print("      new_message - 新消息")
    print("      system_message - 系统消息")
    print("      notification - 通知推送")
    print("      user_status_updated - 状态更新")
    print()
    print("  HTTP API:")
    print("    POST /auth/login - 用户登录")
    print("    GET  /api/rooms/<id>/messages - 获取消息历史")
    print("    GET  /api/users/online - 获取在线用户")
    print("    POST /api/notification - 发送通知")
    print()
    print("  使用说明:")
    print("    1. 访问 http://localhost:5013 打开聊天界面")
    print("    2. 先调用 /auth/login 获取JWT令牌")
    print("    3. 使用令牌连接WebSocket")
    print("    4. 加入房间开始聊天")
    print("=" * 60)
    
    app.socketio.run(
        app,
        host='0.0.0.0',
        port=5013,
        debug=True
    )